package com.ljb.android.comm.weiget.page

import android.content.Context
import android.content.res.TypedArray
import android.graphics.Color
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.ProgressBar
import android.widget.TextView
import androidx.annotation.LayoutRes
import com.ljb.android.comm.R
import java.util.*
import kotlin.collections.HashMap


/**
 * 页面切换管理的Layout
 * Created by Ljb on 2016/1/8.
 */
class PageStateLayout : FrameLayout {

    companion object {

        const val TAG_DEFAULT = "TAG_DEFAULT"

        private val mTagResMap: MutableMap<String, MutableMap<PageState, Int>> = HashMap()

        fun setDefaultEmptyLayout(@LayoutRes resId: Int, tag: String = TAG_DEFAULT) {
            if (resId == 0) return
            var resMap = mTagResMap[tag]
            if (resMap == null) {
                resMap = EnumMap(PageState::class.java)
            }
            resMap[PageState.STATE_EMPTY] = resId
            mTagResMap[tag] = resMap
        }

        fun setDefaultErrorLayout(@LayoutRes resId: Int, tag: String = TAG_DEFAULT) {
            if (resId == 0) return
            var resMap = mTagResMap[tag]
            if (resMap == null) {
                resMap = EnumMap(PageState::class.java)
            }
            resMap[PageState.STATE_ERROR] = resId
            mTagResMap[tag] = resMap
        }

        fun setDefaultLoadLayout(@LayoutRes resId: Int, tag: String = TAG_DEFAULT) {
            if (resId == 0) return
            var resMap = mTagResMap[tag]
            if (resMap == null) {
                resMap = EnumMap(PageState::class.java)
            }
            resMap[PageState.STATE_LOADING] = resId
            mTagResMap[tag] = resMap
        }

    }

    private var mCurPageState = PageState.STATE_SUCCESS
    private var mLoadingResId: Int = -1
    private var mErrorResId: Int = -1
    private var mEmptyResId: Int = -1
    private var mContentResId: Int = -1
    private lateinit var mLoadingView: View
    private lateinit var mErrorView: View
    private lateinit var mEmptyView: View
    private lateinit var mContentView: View
    private var mTag = TAG_DEFAULT

    constructor(context: Context, tag: String = TAG_DEFAULT) : super(context) {
        mTag = tag
        init()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        initAttr(context.obtainStyledAttributes(attrs, R.styleable.PageStateLayout))
        init()
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        initAttr(context.obtainStyledAttributes(attrs, R.styleable.PageStateLayout))
        init()
    }

    private fun initAttr(typedArray: TypedArray) {
        mTag = typedArray.getNonResourceString(R.styleable.PageStateLayout_page_tag) ?: TAG_DEFAULT
        mLoadingResId = typedArray.getResourceId(R.styleable.PageStateLayout_page_load, -1)
        mEmptyResId = typedArray.getResourceId(R.styleable.PageStateLayout_page_empty, -1)
        mErrorResId = typedArray.getResourceId(R.styleable.PageStateLayout_page_error, -1)
        mContentResId = typedArray.getResourceId(R.styleable.PageStateLayout_page_content, -1)
    }

    private fun init() {
        initLoadingView()
        initEmptyView()
        initErrorView()
        initContentView()
        //默认成功页面
        setPage(PageState.STATE_SUCCESS)
    }

    /**
     * 初始化内容页面
     * */
    private fun initContentView() {
        if (mContentResId != -1) {
            mContentView = LayoutInflater.from(context).inflate(mContentResId, this, false)
        } else {
            val defContentView = getDefTextView()
            defContentView.text = context.resources.getString(R.string.page_content_msg)
            mContentView = defContentView
        }
        mContentView.visibility =
            if (mCurPageState == PageState.STATE_SUCCESS) View.VISIBLE else View.GONE
    }


    /**
     * 初始化错误界面
     */
    private fun initErrorView() {
        if (mErrorResId != -1) {
            mErrorView = LayoutInflater.from(context).inflate(mErrorResId, this, false)
        } else {
            val resMap = mTagResMap[mTag]
            if (!resMap.isNullOrEmpty()) {
                mErrorResId = resMap[PageState.STATE_ERROR] ?: -1
                if (mErrorResId != -1) {
                    mErrorView = LayoutInflater.from(context).inflate(mErrorResId, this, false)
                } else {
                    val defErrorView = getDefTextView()
                    defErrorView.text = context.resources.getString(R.string.page_error_msg)
                    mErrorView = defErrorView
                }
            } else {
                val defErrorView = getDefTextView()
                defErrorView.text = context.resources.getString(R.string.page_error_msg)
                mErrorView = defErrorView
            }
        }
        mErrorView.visibility =
            if (mCurPageState == PageState.STATE_ERROR) View.VISIBLE else View.GONE

        mErrorView.findViewById<View?>(R.id.page_retry)?.setOnClickListener {
            mRetryPageListener?.invoke()
        }
    }

    /**
     * 初始化空界面
     */
    private fun initEmptyView() {
        if (mEmptyResId != -1) {
            mEmptyView = LayoutInflater.from(context).inflate(mEmptyResId, this, false)
        } else {
            val resMap = mTagResMap[mTag]
            if (!resMap.isNullOrEmpty()) {
                mEmptyResId = resMap[PageState.STATE_EMPTY] ?: -1
                if (mEmptyResId != -1) {
                    mEmptyView = LayoutInflater.from(context).inflate(mEmptyResId, this, false)
                } else {
                    val defEmptyView = getDefTextView()
                    defEmptyView.text = context.resources.getString(R.string.page_empty_msg)
                    mEmptyView = defEmptyView
                }
            } else {
                val defEmptyView = getDefTextView()
                defEmptyView.text = context.resources.getString(R.string.page_empty_msg)
                mEmptyView = defEmptyView
            }
        }
        mEmptyView.visibility =
            if (mCurPageState == PageState.STATE_EMPTY) View.VISIBLE else View.GONE
    }

    /**
     * 初始化加载中界面
     */
    private fun initLoadingView() {
        if (mLoadingResId != -1) {
            mLoadingView = LayoutInflater.from(context).inflate(mLoadingResId, this, false)
        } else {
            val resMap = mTagResMap[mTag]
            if (!resMap.isNullOrEmpty()) {
                mLoadingResId = resMap[PageState.STATE_LOADING] ?: -1
                if (mLoadingResId != -1) {
                    mLoadingView = LayoutInflater.from(context).inflate(mLoadingResId, this, false)
                } else {
                    val defLoadingView = ProgressBar(context)
                    val widthAndHeight = dip2px(context, 40f)
                    val layoutParams = LayoutParams(widthAndHeight, widthAndHeight)
                    layoutParams.gravity = Gravity.CENTER
                    defLoadingView.layoutParams = layoutParams
                    mLoadingView = defLoadingView
                }
            } else {
                val defLoadingView = ProgressBar(context)
                val widthAndHeight = dip2px(context, 40f)
                val layoutParams = LayoutParams(widthAndHeight, widthAndHeight)
                layoutParams.gravity = Gravity.CENTER
                defLoadingView.layoutParams = layoutParams
                mLoadingView = defLoadingView
            }
        }
        mLoadingView.visibility =
            if (mCurPageState == PageState.STATE_LOADING) View.VISIBLE else View.GONE
    }


    /**
     * 根据状态显示界面
     */
    private fun updatePage(pageState: PageState) {
        changePageStatus(pageState, mContentView, PageState.STATE_SUCCESS)
        changePageStatus(pageState, mErrorView, PageState.STATE_ERROR)
        changePageStatus(pageState, mEmptyView, PageState.STATE_EMPTY)
        changePageStatus(pageState, mLoadingView, PageState.STATE_LOADING)
        mCurPageState = pageState
    }

    /**
     * 检测要显示的页面状态，并添加View到页面上
     * */
    private fun changePageStatus(
        targetPageState: PageState,
        view: View?,
        viewPageState: PageState
    ) {
        view?.apply {
            visibility = if (targetPageState == viewPageState) {
                if (parent == null) {
                    addView(view)
                }
                View.VISIBLE
            } else {
                View.GONE
            }
        }
    }

    fun setPage(pageState: PageState) {
        updatePage(pageState)
    }

    fun getPageState() = mCurPageState

    fun setContentView(resId: Int) {
        checkPreViewInParent(mContentView)
        mContentResId = resId
        initContentView()
        updatePage(mCurPageState)
    }


    fun setContentView(view: View) {
        checkPreViewInParent(mContentView)
        mContentResId = -1
        mContentView = view
        updatePage(mCurPageState)
    }

    fun setErrorView(resId: Int) {
        checkPreViewInParent(mErrorView)
        mErrorResId = resId
        initErrorView()
        updatePage(mCurPageState)
    }

    fun setErrorView(view: View) {
        checkPreViewInParent(mErrorView)
        mErrorResId = -1
        mErrorView = view
        updatePage(mCurPageState)
    }

    fun setLoadView(resId: Int) {
        checkPreViewInParent(mLoadingView)
        mLoadingResId = resId
        initLoadingView()
        updatePage(mCurPageState)
    }

    fun setLoadView(view: View) {
        checkPreViewInParent(mLoadingView)
        mLoadingResId = -1
        mLoadingView = view
        updatePage(mCurPageState)
    }

    fun setEmptyView(resId: Int) {
        checkPreViewInParent(mEmptyView)
        mEmptyResId = resId
        initEmptyView()
        updatePage(mCurPageState)
    }

    fun setEmptyView(view: View) {
        checkPreViewInParent(mEmptyView)
        mEmptyResId = -1
        mEmptyView = view
        updatePage(mCurPageState)
    }


    fun getPageView(page: PageState): View {
        return when (page) {
            PageState.STATE_SUCCESS -> mContentView
            PageState.STATE_LOADING -> mLoadingView
            PageState.STATE_ERROR -> mErrorView
            PageState.STATE_EMPTY -> mEmptyView
        }
    }


    private fun checkPreViewInParent(preView: View?) {
        if (preView != null && preView.parent != null) {
            removeView(preView)
        }
    }

    private fun getDefTextView(): TextView {
        val tv = TextView(context)
        tv.layoutParams =
            LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
        tv.setTextColor(Color.parseColor("#666666"))
        tv.gravity = Gravity.CENTER
        return tv
    }


    private fun dip2px(context: Context, dip: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dip * scale + 0.5f).toInt()
    }


    private var mRetryPageListener: (() -> Unit)? = null

    fun setRetryPageListener(listener: () -> Unit) {
        mRetryPageListener = listener
    }

}
